﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace Genuilder.Extensibility
{
	public class DirectoryCodeRepository : CodeRepositoryBase
	{
		public class CodeItemMemento
		{
			public CodeItemState State
			{
				get;
				set;
			}
			public string FileName
			{
				get;
				set;
			}
			public DateTime LastModified
			{
				get;
				set;
			}
		}

		public DirectoryCodeRepository(CodeItemMementoRepository repository)
		{
			if(repository == null)
				throw new ArgumentNullException("repository");
			_MementoRepository = repository;
			BaseDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
		}
		public DirectoryInfo BaseDirectory
		{
			get;
			set;
		}
		private readonly CodeItemMementoRepository _MementoRepository;
		public CodeItemMementoRepository MementoRepository
		{
			get
			{
				return _MementoRepository;
			}
		}

		private readonly List<string> _Files = new List<string>();
		public List<string> Files
		{
			get
			{
				return _Files;
			}
		}
		protected override CodeItem CreateCodeItem(string name, CodeItemState state)
		{
			return new FileCodeItem(name, FullPathOf(name), state);
		}

		String FullPathOf(string name)
		{
			return Path.Combine(BaseDirectory.FullName, name);
		}

		protected override IEnumerable<CodeItemHistory> GetCodeItemHistories()
		{
			List<CodeItemHistory> histories = new List<CodeItemHistory>();
			var mementos = MementoRepository.LoadCodeItemMementos();

			foreach(var memento in mementos)
			{
				CodeItemHistory history = new CodeItemHistory(CreateFromMemento(memento));
				FileCodeItem fileCodeItem = (FileCodeItem)history.CodeItem;
				if(!fileCodeItem.File.Exists)
					history.NewState = CodeItemState.Deleted;
				else
				{
					history.Modified = fileCodeItem.LastModified > memento.LastModified;
					history.NewState = Files.Select(f => new FileInfo(f).FullName).Contains(FullPathOf(fileCodeItem.Name)) ? CodeItemState.Exist : CodeItemState.Excluded;
				}
				histories.Add(history);
			}


			var newFiles = Files.Where(f => !mementos.Any(m => m.FileName == f));
			foreach(var newFile in newFiles)
			{
				var history = new CodeItemHistory(new FileCodeItem(PathUtil.RelativePathTo(BaseDirectory.FullName ,newFile), newFile, CodeItemState.Exist));
				history.NewState = CodeItemState.Exist;
				history.Modified = true;
				histories.Add(history);
			}
			return histories;
		}

		private CodeItem CreateFromMemento(CodeItemMemento memento)
		{
			return CreateCodeItem(memento.FileName, memento.State);
		}

		protected override void OnInitialized(IEnumerable<CodeItem> trackedItems)
		{
			var mementos = trackedItems.Where(i => i.State == CodeItemState.Exist).Select(i => ToMemento(i));
			MementoRepository.SaveCodeItemMementos(mementos);
		}



		private CodeItemMemento ToMemento(CodeItem item)
		{
			FileCodeItem itemFile = item as FileCodeItem;
			return new CodeItemMemento()
			{
				FileName = itemFile.Name,
				LastModified = itemFile.LastModified,
				State = itemFile.State
			};
		}
	}

	public class FileCodeItem : CodeItem
	{
		public FileCodeItem(string name, string fullPath, CodeItemState initialState)
			: base(name, initialState)
		{
			_FilePath = fullPath;
		}

		String _FilePath;
		public FileInfo File
		{
			get
			{
				return new FileInfo(_FilePath);
			}
		}


		string _Content;
		public override string ContentCore
		{
			get
			{
				if(_Content == null)
					_Content = LoadFileContent();
				return _Content;
			}
			set
			{
				SaveFileContent(value);
				_Content = value;
				OnContentChanged();
			}
		}

		public DateTime LastModified
		{
			get
			{
				return File.LastWriteTime;
			}
		}


		private void SaveFileContent(string value)
		{
			System.IO.File.WriteAllText(File.FullName, value);
		}

		private string LoadFileContent()
		{
			return System.IO.File.ReadAllText(File.FullName);
		}
	}
}
